use axum::http::StatusCode;
use axum::response::{IntoResponse, Redirect, Response};
use crate::support::response::AppResponse;

pub type AppResult<T> = Result<T, AppError>;

#[derive(Debug,thiserror::Error )]
pub enum AppError{
    #[error("Not Found")]
    NotFound,
    #[error("Method not allowed")]
    MethodNotAllowed,
    #[error("Internal Server Error: {0}")]
    InternalError(#[from] anyhow::Error),
    #[error("URL Parse Error: {0}")]
    UrlParserError(#[from] url::ParseError),
    #[error("Request Error: {0}")]
    ReqWestError(#[from] reqwest::Error),
    #[error("Session Error: {0}")]
    SessionError(#[from] tower_sessions::session::Error),
    #[error("Authentication Required")]
    AuthenticationRequired,
    #[error("AuthFlowError: {0}")]
    AuthFlowError(String),
    #[error("AuthServerError : {0}")]
    AuthServerError(String),
}

impl AppError{
    pub fn status_code(&self) -> StatusCode {
        match self{
            AppError::NotFound => StatusCode::NOT_FOUND,
            AppError::AuthenticationRequired | AppError::AuthServerError(_)=> StatusCode::UNAUTHORIZED,
            AppError::MethodNotAllowed => StatusCode::NOT_FOUND,
            AppError::InternalError(_)|AppError::UrlParserError(_) |AppError::ReqWestError(_)
                |AppError::SessionError(_)=> StatusCode::INTERNAL_SERVER_ERROR,
            AppError::AuthFlowError(_) => StatusCode::BAD_REQUEST,
        }
    }
}

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let status_code = self.status_code();
        let body = axum::Json(AppResponse::<()>::err(self.to_string()));
        match self{
            AppError::AuthenticationRequired=>Redirect::temporary("/login").into_response(),
            _=>(status_code, body).into_response()
        }
    }
}